using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace OpenWaves.Web.Controls
{
    [Obsolete("Use NavigationView control with Model property set to an apriopriate instance of object derived from INavigationViewModel.", false)]
    [ParseChildren(true)]
    [PersistChildren(false)]
    public abstract class Navigation<T> : NavigationView<T> where T : ITreeNode<T>
    {
        [Obsolete("Use ExpandedNodeTemplate instead.", true)]
        public ITemplate SelectedNodeTemplate
        {
            get { return this.ExpandedNodeTemplate; }
            set { this.ExpandedNodeTemplate = value; }
        }

        public override object DataSource
        {
            get { return base.DataSource; }
            set
            {
                base.DataSource = value;
                this.Model = new NavigationViewModel(value as IEnumerable<T>, this.GetNodeStatus, this.IsNodeVisible);
            }
        }

        private class NavigationViewModel : INavigationViewModel<T>
        {
            private readonly Func<T, NavigationNodeState> getNodeStatus;
            private readonly Func<T, bool> isNodeVisible;

            public NavigationViewModel(IEnumerable<T> rootNodes, Func<T, NavigationNodeState> getNodeStatus, Func<T, bool> isNodeVisible)
            {
                this.RootNodes = rootNodes;
                this.getNodeStatus = getNodeStatus;
                this.isNodeVisible = isNodeVisible;
            }

            public IEnumerable<T> RootNodes { get; private set; }

            public NavigationNodeState GetNodeState(T node)
            {
                return this.getNodeStatus(node);
            }

            public bool IsNodeVisible(T node)
            {
                return this.isNodeVisible(node);
            }
        }

        protected override bool IsNodeVisible(T node)
        {
            return true;
        }

        protected abstract NavigationNodeState GetNodeStatus(T node);
    }

    [Obsolete("Use NavigationView control with Model property set to an apriopriate instance of object derived from INavigationViewModel.", false)]
    public class Navigation : Navigation<INavigationNode>
    {
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate NodeTemplate
        {
            get { return base.NodeTemplate; }
            set { base.NodeTemplate = value; }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate FirstLevelNodeTemplate
        {
            get { return base.FirstLevelNodeTemplate; }
            set { base.FirstLevelNodeTemplate = value; }
        }


        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate SecondLevelNodeTemplate
        {
            get { return base.SecondLevelNodeTemplate; }
            set { base.SecondLevelNodeTemplate = value; }
        }


        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate ThirdLevelNodeTemplate
        {
            get { return base.ThirdLevelNodeTemplate; }
            set { base.ThirdLevelNodeTemplate = value; }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate FourthLevelNodeTemplate
        {
            get { return base.FourthLevelNodeTemplate; }
            set { base.FourthLevelNodeTemplate = value; }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate FifthLevelNodeTemplate
        {
            get { return base.FifthLevelNodeTemplate; }
            set { base.FifthLevelNodeTemplate = value; }
        }

        [Obsolete("Use ExpandedNodeTemplate instead.")]
        public new ITemplate SelectedNodeTemplate
        {
            get { return base.SelectedNodeTemplate; }
            set { base.SelectedNodeTemplate = value; }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate ExpandedNodeTemplate
        {
            get { return base.ExpandedNodeTemplate; }
            set { base.ExpandedNodeTemplate = value; }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [TemplateContainer(typeof(NavigationNodeContainer<INavigationNode>))]
        public new ITemplate CurrentNodeTemplate
        {
            get { return base.CurrentNodeTemplate; }
            set { base.CurrentNodeTemplate = value; }
        }

        protected override NavigationNodeState GetNodeStatus(INavigationNode node)
        {
            if (this.IsNodeCurrent(node))
                return NavigationNodeState.Current;
            if (this.IsNodeExpanded(node))
                return NavigationNodeState.Expanded;
            return NavigationNodeState.Normal;
        }

        protected virtual bool IsNodeExpanded(INavigationNode node)
        {
            return node.GetChildrenRecursively().Any(this.IsNodeCurrent);
        }

        protected virtual bool IsNodeCurrent(INavigationNode node)
        {
            var nodeAbsoluteUrl = node.Url.ResolveAgainst(this.Page.Request.GetRawUrl());

            return Equals(this.ResolveCurrentUrl(), nodeAbsoluteUrl);
        }

        protected override IEnumerable<INavigationNode> AdaptHierarchicalEnumerable(IHierarchicalEnumerable hierarchicalEnumerable)
        {
            return HierarchicalEnumerableToNavigationNodeAdapter.From(hierarchicalEnumerable);
        }

        protected override bool IsNodeVisible(INavigationNode node)
        {
            return node.IsVisibleInMenu;
        }

        protected virtual AbsoluteUrl ResolveCurrentUrl()
        {
            if (this.IsBoundUsingDataSourceID)
            {
                var dataSource = this.GetDataSource() as SiteMapDataSource;
                if (dataSource != null)
                {
                    var currentNode = dataSource.Provider.CurrentNode;
                    if (currentNode != null)
                    {
                        return Url.ParseRelative(currentNode.Url).ResolveAgainst(this.Page.Request.GetRawUrl());
                    }
                }

                return null;
            }
            else
            {
                return this.Page.Request.GetRawUrl().GetBuilder().ClearQuery().SetFragment("").ToUrl();
            }
        }
    }
}